package customer

import (
	"context"
	"git.mycaigou.com/gfyx/common/tenant_db"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/constants"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/utils"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/dto/aggregation"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/base/user"
	"git.myscrm.cn/golang/stark/v4"
	"gorm.io/gorm"
	"time"
)

type customerManageRepository struct {
	tenant_db.TenantDB
}

func NewCustomerManageRepository() CustomerManageRepositoryIface {
	return &customerManageRepository{}
}

func (r *customerManageRepository) GetCustomerByOrganizingCodeOrCompanyName(ctx context.Context, id int64, organizingCode, companyName string) (*CustomerPo, error) {
	customerPo := &CustomerPo{}
	err := r.GetTenantDB(ctx).
		Where("id <> ?", id).
		Where("is_deleted = ?", constants.IsDeletedFalse).
		Where("(organizing_code =? or company_name =?)", organizingCode, companyName).
		First(customerPo).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		stark.Logger.Errorf(ctx, "method:GetCustomerByOrganizingCodeOrCompanyName,err:", err)
		return nil, err
	}
	return customerPo, nil
}

func (r *customerManageRepository) GetCustomerInfo(ctx context.Context, condition map[string]interface{}) (*CustomerPo, error) {
	customerPo := &CustomerPo{}
	err := r.GetTenantDB(ctx).
		Where(condition).
		First(customerPo).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		stark.Logger.Errorf(ctx, "method:GetCustomerInfo,err:", err)
		return nil, err
	}
	return customerPo, nil
}

func (r *customerManageRepository) QueryCustomerList(ctx context.Context, condition map[string]interface{}, pageInfo *utils.PageInfo) (int64, []*CustomerListItemPo, error) {
	// 客户主表
	filedStr := "c.id,c.company_name,c.organizing_code,c.company_logo,c.company_type,c.business_status,c.province,c.province_code,c.city,c.city_code,c.group,c.ycg_company_id,c.top_company_name,c.top_organizing_code as top_company_organizing_code,c.credit_level,c.created_on"
	// 拼上负责人名称 和 创建人名称
	filedStr += ",u1.id as responsible_user_id, u1.name as responsible_user_name"
	filedStr += ",c.created_by as created_by, u2.name as created_by_user_name"
	// 企业指标
	filedStr += ",i.clue_cnt,i.report_cnt,i.bid_cnt_2year,i.take_land_cnt_2year,i.commence_permit_cnt_2year,i.sell_project_cnt_2year,i.cooperation_case_cnt_2year"
	// 企业标签
	filedStr += ",t.company_label,t.company_identity,t.company_level"
	db := r.GetTenantDB(ctx).Table(CustomerPo{}.TableName() + " c").
		Select(filedStr).
		Joins("left join " + CustomerIndexPo{}.TableName() + " i on c.id = i.customer_id").
		Joins("left join " + user.GfyxUserPo{}.TableName() + " u1 on c.responsible_user_id = u1.id").
		Joins("left join " + user.GfyxUserPo{}.TableName() + " u2 on c.created_by = u2.id").
		Joins("left join " + CustomerTagPo{}.TableName() + " t on c.id = t.customer_id")

	// 处理 where 条件
	condition["c.is_deleted"] = constants.IsDeletedFalse
	condition["i.is_deleted"] = constants.IsDeletedFalse
	condition["t.is_deleted"] = constants.IsDeletedFalse
	if keyword, ok := condition["keyword"].(string); ok {
		db = db.Where("c.company_name like ?", "%"+keyword+"%")
		delete(condition, "keyword")
	}
	// 处理公司名称
	if companyList, ok := condition["company_name_list"].([]string); ok {
		db = db.Where("c.company_name in (?)", companyList)
		delete(condition, "company_name_list")
	}
	// 处理地区字段
	if areaCodes, ok := condition["area_codes"].([]string); ok {
		db = db.Where("(c.province_code in (?) or c.city_code in (?))", areaCodes, areaCodes)
		delete(condition, "area_codes")
	}
	// 处理企业标签 company_label
	if companyLabel, ok := condition["company_label"].(string); ok {
		db = db.Where("FIND_IN_SET(?, t.company_label)", companyLabel)
		delete(condition, "company_label")
	}
	if companyLevel, ok := condition["company_level"].(string); ok {
		db = db.Where("FIND_IN_SET(?, t.company_level)", companyLevel)
		delete(condition, "company_level")
	}
	if companyIdentity, ok := condition["company_identity"].(string); ok {
		db = db.Where("FIND_IN_SET(?, t.company_identity)", companyIdentity)
		delete(condition, "company_identity")
	}
	if companyTypes, ok := condition["company_types"].([]string); ok {
		db = db.Where("c.company_type in (?)", companyTypes)
		delete(condition, "company_types")
	}
	if userIds, ok := condition["responsible_user_ids"].([]int64); ok {
		db = db.Where("c.responsible_user_id in (?)", userIds)
		delete(condition, "responsible_user_ids")
	}
	if groups, ok := condition["groups"].([]string); ok {
		db = db.Where("c.group in (?)", groups)
		delete(condition, "groups")
	}
	if organizingCodes, ok := condition["organizing_codes"].([]string); ok {
		db = db.Where("c.organizing_code in (?)", organizingCodes)
		delete(condition, "organizing_codes")
	}
	db = db.Where(condition)
	var count int64
	var queryList []*CustomerListItemPo
	err := db.Count(&count).Error
	if err != nil {
		return 0, nil, err
	}

	if pageInfo != nil && pageInfo.Page > 0 && pageInfo.PageSize > 0 {
		db = db.Offset((pageInfo.Page - 1) * pageInfo.PageSize).Limit(pageInfo.PageSize)
	}
	if err = db.Order("c.id desc").Find(&queryList).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return 0, nil, nil
		}
		return 0, nil, err
	}
	return count, queryList, nil
}

func (r *customerManageRepository) QuerySimpleCustomerList(ctx context.Context, condition map[string]interface{}, pageInfo *utils.PageInfo) (int64, []*CustomerPo, error) {
	db := r.GetTenantDB(ctx).Table(CustomerPo{}.TableName())
	if organizingCodes, ok := condition["organizing_codes"].([]string); ok {
		db = db.Where("organizing_code in (?)", organizingCodes)
		delete(condition, "organizing_codes")
	}
	db.Where(condition)
	var count int64
	var queryList []*CustomerPo
	err := db.Count(&count).Error
	if err != nil {
		return 0, nil, err
	}
	if pageInfo != nil && pageInfo.Page > 0 && pageInfo.PageSize > 0 {
		db = db.Offset((pageInfo.Page - 1) * pageInfo.PageSize).Limit(pageInfo.PageSize)
	}
	if err = db.Find(&queryList).Order("c.id desc").Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return 0, nil, nil
		}
		return 0, nil, err
	}
	return count, queryList, nil
}

func (r *customerManageRepository) SaveCustomer(ctx context.Context, po *CustomerPo) (*CustomerPo, error) {
	err := r.GetTenantDB(ctx).Table(po.TableName()).Save(po).Error
	if err != nil {
		stark.Logger.Errorf(ctx, "SaveCustomer save data : %+v, error: %+v", po, err)
		return nil, err
	}
	return po, nil
}

func (r *customerManageRepository) SaveCustomerGroup(ctx context.Context, userId, customerId int64, groups []string) error {
	po := &CustomerGroupPo{}
	// 先删除客户分组
	err := r.GetTenantDB(ctx).Table(po.TableName()).
		Where("customer_id =?", customerId).
		Where("is_deleted =?", constants.IsDeletedFalse).
		Update("is_deleted", constants.IsDeletedTrue).Error
	if err != nil {
		stark.Logger.Errorf(ctx, "SaveCustomerGroup delete data : %+v, error: %+v", po, err)
		return err
	}
	groupPoList := make([]*CustomerGroupPo, 0)
	for _, group := range groups {
		groupPo := &CustomerGroupPo{
			CustomerId: customerId,
			GroupName:  group,
			CreatedBy:  userId,
			CreatedOn:  time.Now(),
			ModifiedBy: userId,
			ModifiedOn: time.Now(),
			IsDeleted:  constants.IsDeletedFalse,
		}
		groupPoList = append(groupPoList, groupPo)
	}
	// 如果没有分组，就默认添加一个分组
	if len(groupPoList) == 0 {
		groupPo := &CustomerGroupPo{
			CustomerId: customerId,
			GroupName:  constants.CustomerGroupDefaultName,
			CreatedBy:  userId,
			CreatedOn:  time.Now(),
			ModifiedBy: userId,
			ModifiedOn: time.Now(),
			IsDeleted:  constants.IsDeletedFalse,
		}
		groupPoList = append(groupPoList, groupPo)
	}
	// 再新增客户分组
	err = r.GetTenantDB(ctx).Table(po.TableName()).Save(&groupPoList).Error
	if err != nil {
		stark.Logger.Errorf(ctx, "SaveCustomerGroup save data : %+v, error: %+v", groupPoList, err)
		return err
	}

	return nil
}

func (r *customerManageRepository) SaveCustomerIndex(ctx context.Context, po *CustomerIndexPo) error {
	// 查找数据
	var queryPo = &CustomerIndexPo{}
	err := r.GetTenantDB(ctx).Table(po.TableName()).Where("customer_id = ? and is_deleted = ?", po.CustomerId, constants.IsDeletedFalse).First(queryPo).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		stark.Logger.Errorf(ctx, "SaveCustomerIndex find data : %+v, error: %+v", po, err)
		return err
	}
	if err == gorm.ErrRecordNotFound {
		// 插入
		err = r.GetTenantDB(ctx).Table(po.TableName()).Create(po).Error
		if err != nil {
			stark.Logger.Errorf(ctx, "SaveCustomerIndex create data : %+v, error: %+v", po, err)
			return err
		}
	} else {
		// 更新
		err = r.GetTenantDB(ctx).Table(po.TableName()).Where("customer_id =? and is_deleted =?", po.CustomerId, constants.IsDeletedFalse).Updates(po).Error
		if err != nil {
			stark.Logger.Errorf(ctx, "SaveCustomerIndex update data : %+v, error: %+v", po, err)
			return err
		}
	}
	return nil
}

func (r *customerManageRepository) SaveCustomerTags(ctx context.Context, po *CustomerTagPo) error {
	queryPo := &CustomerTagPo{}
	err := r.GetTenantDB(ctx).Table(CustomerTagPo{}.TableName()).
		Where("customer_id =? and is_deleted =?", po.CustomerId, constants.IsDeletedFalse).
		First(queryPo).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			// 插入
			po.CreatedOn = po.ModifiedOn
			po.CreatedBy = po.ModifiedBy
			err = r.GetTenantDB(ctx).Table(CustomerTagPo{}.TableName()).Create(po).Error
			if err != nil {
				stark.Logger.Errorf(ctx, "SaveCustomerTags create data : %+v, error: %+v", po, err)
				return err
			}
		} else {
			stark.Logger.Errorf(ctx, "query customer_tag: %d, error: %+v", po.CustomerId, err)
			return err
		}
	}
	if queryPo.Id > 0 {
		po.Id = queryPo.Id
		po.CreatedOn = queryPo.CreatedOn
		po.CreatedBy = queryPo.CreatedBy
		err = r.GetTenantDB(ctx).Table(CustomerTagPo{}.TableName()).Save(po).Error
		if err != nil {
			stark.Logger.Errorf(ctx, "SaveCustomerTags save data : %+v, error: %+v", po, err)
			return err
		}
	}
	return nil
}

func (r *customerManageRepository) DeleteCustomer(ctx context.Context, userId, id int64) error {
	updateData := map[string]interface{}{"is_deleted": constants.IsDeletedTrue, "modified_by": userId, "modified_on": time.Now()}
	db := r.GetTenantDB(ctx)
	db = db.Begin()
	defer func() {
		db.Rollback()
	}()
	// 1. 删除客户主表
	err := db.Table(CustomerPo{}.TableName()).
		Where("id = ? and is_deleted =?", id, constants.IsDeletedFalse).
		Updates(updateData).Error
	if err != nil {
		stark.Logger.Errorf(ctx, "SaveCustomer delete data : %d, error: %+v", id, err)
		return err
	}
	// 2. 删除客户标签
	err = db.Table(CustomerTagPo{}.TableName()).
		Where("customer_id = ? and is_deleted =?", id, constants.IsDeletedFalse).
		Updates(updateData).Error
	if err != nil {
		stark.Logger.Errorf(ctx, "SaveCustomerTag delete data : %d, error: %+v", id, err)
		return err
	}
	// 3. 删除客户指标
	err = db.Table(CustomerIndexPo{}.TableName()).
		Where("customer_id = ? and is_deleted =?", id, constants.IsDeletedFalse).
		Updates(updateData).Error
	if err != nil {
		stark.Logger.Errorf(ctx, "SaveCustomerIndex delete data : %d, error: %+v", id, err)
		return err
	}

	db.Commit()
	return nil
}

// GetCustomerGroup 不分组，最多限制返回 500 个
func (r *customerManageRepository) GetCustomerGroup(ctx context.Context) ([]string, error) {
	groups := make([]string, 0)
	err := r.GetTenantDB(ctx).Table(CustomerPo{}.TableName()).
		Select("`group`").
		Group("group").
		Limit(500).
		Pluck("group", &groups).Error
	if err != nil {
		stark.Logger.Errorf(ctx, "GetCustomerGroup find data : %+v, error: %+v", groups, err)
		return nil, err
	}
	return groups, nil
}

func (r *customerManageRepository) CustomerUseRank(ctx context.Context, beginDate, endDate string, pageInfo *utils.PageInfo) ([]*aggregation.UseRankItem, error) {
	var list []*aggregation.UseRankItem
	db := r.GetTenantDB(ctx).Table(CustomerPo{}.TableName()).Select("created_by as user_id, count(1) as total").
		Where("created_on between ? and ? and created_by <> 0 and is_deleted = ?", beginDate, endDate, constants.IsDeletedFalse)

	if pageInfo != nil && pageInfo.Page > 0 && pageInfo.PageSize > 0 {
		db = db.Offset((pageInfo.Page - 1) * pageInfo.PageSize).Limit(pageInfo.PageSize)
	}
	err := db.Group("created_by").Order("total desc").Find(&list).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		return nil, err
	}
	return list, nil
}

func (r *customerManageRepository) GetCurrentMonthCustomerCount(ctx context.Context, userId int64, monthStart string, monthEnd string) (int64, error) {
	var total int64
	err := r.GetTenantDB(ctx).Table(CustomerPo{}.TableName()).Where("created_by = ? and created_on >= ? and created_on < ? and is_deleted = ?",
		userId, monthStart, monthEnd, constants.IsDeletedFalse).Count(&total).Error
	if err != nil {
		return 0, err
	}
	return total, nil
}
